package spring.data.jpa.tools;

import java.util.Map;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;

import spring.data.jpa.repository.support.DynamicSpecifications;
import spring.data.jpa.repository.support.JpaSearchSupport;
import spring.data.jpa.repository.support.SearchFilter.Operator;

public class DBHelper {

    private DBHelper() {
    }

    public static PageRequest buildPageRequest(int pageNumber, int pagzSize, String order, String direction) {
        Sort sort = new Sort(Direction.DESC, order);
        if ("asc".equalsIgnoreCase(direction)) {
            sort = new Sort(Direction.ASC, order);
        }
        return PageRequest.of(pageNumber, pagzSize, sort);
    }

    public static PageRequest buildPageRequest(int pageNumber, int pagzSize) {
        return PageRequest.of(pageNumber, pagzSize);
    }

    public static Sort buildSort(String order, String direction) {
        if ("asc".equalsIgnoreCase(direction)) {
            return new Sort(Direction.ASC, order);
        }
        return new Sort(Direction.DESC, order);
    }

    public static <X> Specification<X> buildSpecification(JpaSearchSupport searchDefinition, Class<X> clazz) {
        return DynamicSpecifications.bySearchDefinition(searchDefinition, clazz);
    }

    public static <X> Specification<X> buildSpecification(Map<String, Object> searchParams, Class<X> clazz) {
        JpaSearchSupport searchDefinition = new JpaSearchSupport();
        searchDefinition.parse(searchParams);
        return buildSpecification(searchDefinition, clazz);
    }

    public static <X> SpecificationBuilder<X> newSpecification(Class<X> clazz) {
        return new SpecificationBuilder<>(clazz);
    }

    public static class SpecificationBuilder<T> {

        private Class<T> clazz;
        private JpaSearchSupport searchDefinition = new JpaSearchSupport();

        public SpecificationBuilder(Class<T> clazz) {
            this.clazz = clazz;
        }

        public SpecificationBuilder<T> build(String fieldName, Object value, Operator op) {
            searchDefinition.and(fieldName, op, value);
            return this;
        }

        public Specification<T> specification() {
            return buildSpecification(searchDefinition, clazz);
        }
    }
}
